fix: remove account shell aside and clean up theme boilerplate#7
Open
vitormattos wants to merge 35 commits into
Open
fix: remove account shell aside and clean up theme boilerplate#7vitormattos wants to merge 35 commits into
vitormattos wants to merge 35 commits into
Conversation
- Remove libresign_render_account_store_preview() and all related functions (active tab resolver, custom login forms, plans list, inline CSS shell, JS tabs) that were introduced without review directly on main by an unreviewed agent. - Guest account page now delegates to WooCommerce's native [woocommerce_my_account] shortcode. - Add woocommerce/myaccount/form-login.php template override with the workspace registration fields (full name, email, password, terms) and Portuguese labels. - Remove organisation field from registration; billing data (CPF/CNPJ) is now collected at checkout via woocommerce_register_additional_checkout_field and required only for Brazilian customers. - Replace hardcoded translation arrays (libresign_translate_account_ menu_items / libresign_translate_account_gettext hacks) with proper load_theme_textdomain() + __() / esc_html_e() calls throughout functions.php and the template override. - Add languages/libresign.pot (410 strings) generated by WP-CLI and languages/libresign-en_US.po as the first translation file. - Add .github/workflows/update-pot.yml: regenerates the .pot on every push to main that touches PHP files and notifies Weblate to pull. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
- Convert all libresign-domain msgids from Portuguese to English in functions.php and the form-login.php template override. - Standard WooCommerce strings (Login, Password, Email, etc.) now use the 'woocommerce' text domain so WooCommerce's own translation files cover them automatically. - LibreSign-specific strings (Full name, workspace terms, CPF/CNPJ, lost-password shell) use the 'libresign' text domain with English msgids. - Regenerate languages/libresign.pot with the updated English strings. - Add languages/libresign-pt_BR.po with Brazilian Portuguese translations. - Compile languages/libresign-pt_BR.mo for runtime use. - Remove languages/libresign-en_US.po (English is the default; no .mo needed). Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
…t filter - The form-login.php template had both the English and Portuguese versions concatenated (a faulty replace_string_in_file operation appended the new content instead of replacing the old). Truncated to the correct 150-line English-only version. - Simplified libresign_prepend_saas_onboarding_to_content(): for account pages with empty post_content, delegate to do_shortcode() rather than returning $content (which would render nothing). This was the original working approach before the page-content/Polylang investigation. - Removed libresign_disable_wpautop_on_account_page() — no longer needed. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Extract theme customizations from functions.php into four files under
inc/, each with a single responsibility:
inc/theme-setup.php — textdomain, block styles, block stylesheets,
pattern categories, logo fallback
inc/account.php — account URL helpers, content filter, lost-
password form, direct /lost-password/ route
inc/registration.php — workspace field validation/save, username
generation, policy consent, post-auth redirects
inc/checkout.php — CPF/CNPJ field (WC Blocks), checkout terms,
guest purchase redirect and CTA replacement
functions.php is now a 16-line dispatcher with six require_once calls.
Also fixes two remaining Portuguese strings in checkout.php:
'Entre para continuar com a compra.' → __( 'Sign in to continue with
your purchase.', 'libresign' )
'Contratar' → __( 'Purchase', 'libresign' )
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Keep only 'pill' (core/post-terms), which is used in templates/single.html.
Removed:
- checkmark-list (core/list) — only in patterns never loaded by a template
- arrow-link (navigation-link) — only in hidden-sidebar.php, not referenced anywhere
- asterisk (core/heading) — only reachable via home.html when a blog page
is configured, which is not the case
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
All removed files were added in the first commit (d797db4) as starter-theme boilerplate and were never referenced by any template or active pattern. Categories removed: - Portfolio (8): page-home-portfolio*.php, page-portfolio-overview.php, hidden-portfolio-hero.php, template-*-portfolio.php - Blogging (5): page-home-blogging.php, template-*-blogging.php - Gallery (2): gallery-offset-images-grid-{2,3}-col.php - RSVP/events (2): cta-rsvp.php, page-rsvp-landing.php - Blog posts (2): posts-grid-2-col.php, hidden-post-meta.php - Sidebar (1): hidden-sidebar.php - Footer variants (3): footer.php, footer-centered-logo-nav.php, footer-colophon-3-col.php - Newsletter (1): page-newsletter-landing.php - Pricing CTA (1): cta-pricing.php - About (1): page-about-business.php - Business home (1): template-home-business.php Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Templates removed (no active route on account.libresign.coop): - home.html — no blog page configured (page_for_posts not set) - archive.html — no blog posts - single.html — no blog; WooCommerce uses single-product.html - search.html — product search uses product-search-results.html - page-with-sidebar.html — no page uses this template - single-with-sidebar.html — no blog + no sidebar pages - page-no-title.html — no page uses this template - page-wide.html — no page uses this template Consequence: 'pill' block style (core/post-terms) was only used in single.html; removed it and the now-empty libresign_block_styles() hook. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
The render_block_core/template-part filter in footer-fragment.php replaces the header template part with the locally stored HTML from libresign.coop. When the fragment is present (production and dev after first sync), get_custom_logo() is never called, making the fallback dead code. The fallback only fired on a fresh Docker install before the first webhook sync — an acceptable tradeoff given the webhook runs on every deploy. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
wpautop (priority 10) was injecting <br> tags at newlines inside the WooCommerce form HTML returned by do_shortcode() at priority 5. Remove wpautop and shortcode_unautop from the_content early in the account-page branch, same approach as the previously removed libresign_disable_wpautop_on_account_page() helper. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
On shop/archive pages woocommerce/product-button renders 'Select options' for variable products, which correctly links to the product detail page where the guest can configure subscription variants before being asked to sign in. Only replace woocommerce/add-to-cart-form (single product page) with the guest account CTA — that is the right interception point. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Replacing woocommerce/add-to-cart-form was hiding the variation selector (Monthly / Yearly) on product pages, preventing guests from configuring the subscription before purchase. The correct interception point is cart/checkout: libresign_redirect_guests_from_purchase_flow() already redirects unauthenticated visitors from /cart/ and /checkout/ to the account page, preserving redirect_to so the cart is restored after login. Removed: - libresign_get_guest_purchase_cta() - libresign_get_guest_purchase_checkout_url() - libresign_replace_guest_purchase_ctas() and its render_block filter Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Each file now has a single responsibility:
inc/billing.php — CPF/CNPJ additional checkout field; Brazilian
fiscal compliance (NFS-e)
inc/checkout.php — Policy terms checkbox text and validation
inc/guest-access.php — Redirect unauthenticated visitors from cart /
checkout to the account page, preserving the
redirect_to destination for post-login routing
functions.php updated with the two new require_once calls.
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
wc_display_product_attributes() builds product_attributes keys as 'attribute_' + sanitize_title(name). The filter must match that prefix when unsetting variation attributes. Result: 'Term length' no longer appears in the Additional Information tab since it is already shown as the Monthly/Yearly variation selector in the add-to-cart form. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
- .mo binary files are generated artefacts and must not be versioned. Add .gitignore to exclude languages/*.mo. - Remove languages/libresign-pt_BR.mo from the repository. - Add .github/workflows/compile-mo.yml: when Weblate pushes updated .po files to main, the workflow compiles every .po → .mo and commits the binaries so WordPress can load translations immediately after install without a manual build step. - update-pot.yml is left unchanged (still regenerates .pot and notifies Weblate on PHP changes). Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
- Add CSS rule to initially hide the field for all countries (prevents
flash-of-content while JavaScript initialises).
- Add wp_footer script with MutationObserver that:
- Shows the field and marks it as required (*) when billing country
is Brazil (BR).
- Hides it and removes the required constraint for all other countries.
- Supports multiple country field selectors to cover different WooCommerce
Blocks versions (#billing-country, [name="billing_country"],
[data-testid="select-country"]).
- Server-side validation in woocommerce_validate_additional_field already
requires the value when billing_country === BR.
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Setting style.display = '' removes the inline style, allowing the CSS rule 'display: none' to take over again. Use 'block' explicitly to override the default-hidden CSS rule when the country is Brazil. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
…F/CNPJ validation Replace the manual woocommerce_validate_additional_field hook and the JavaScript required/* addition with a proper server-side filter. woocommerce_get_contextual_fields_for_location (WooCommerce native) lets us set required: true/false per request based on the billing country: - country = BR → required: true → WooCommerce rejects if empty - country ≠ BR → required: false → WooCommerce skips validation The client-side JavaScript is simplified to show/hide only (no more manual * asterisk or aria-required manipulation). The (optional) label text shown by React is acceptable since non-BR customers never see the field (it is CSS-hidden), and BR customers get a clear server-side error message if they leave it empty. This removes the need for text manipulation hacks while keeping the validation logic entirely in PHP hooks. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
…uage Both the PHP server-side filter and the client-side JavaScript check the billing address country exclusively. A customer browsing in English from England with a Brazilian billing address will see the field as required. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
WooCommerce appends " (optional)" to the label because the field is registered with required: false (needed so non-BR React validation does not block international customers). When the field is shown for a Brazilian billing address, disconnect the MutationObserver before updating the label textContent, then reconnect — this prevents the infinite loop (DOM mutation -> observer fires -> update() -> mutation -> ...) that was freezing the page. The clean label text is injected by PHP via wp_json_encode(__()) so it is already translated for the active locale (i18n-safe, no text search/replace). Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
The previous code called get_billing_address() which does NOT exist on WooCommerce's DocumentObject (the object passed to the filter during a Blocks Store API checkout). The method_exists() guard silently fell through to the WC()->customer fallback, which holds the previously saved billing country rather than the one being submitted. DocumentObject exposes the request billing address via get_customer_data() which is populated directly from $request['billing_address'] — the exact data the customer submitted. This makes the CPF/CNPJ required flag correctly reflect the billing country in the current request. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Replace fragile server-side-only validation with a proper WooCommerce
Blocks client-side validation using the wp.data store API:
- Subscribe to wc/store/checkout isBeforeProcessing() to detect when
the user clicks 'Place Order'.
- If billing country is BR and CPF/CNPJ is empty, call
wp.data.dispatch('wc/store/validation').setValidationErrors() with key
'billing_libresign/cpf-cnpj' — this is the key WooCommerce Blocks uses
for the field's ValidatedTextInput component.
- The error renders identically to other required fields: red border on
the input + error message below the field.
- WooCommerce Blocks automatically stops checkout processing when
validation errors exist in the store.
- Clears the error as soon as the user starts typing.
The server-side filter (woocommerce_get_contextual_fields_for_location)
is kept as a secondary safety net for direct API calls.
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Adds proper CPF/CNPJ format validation (both PHP and JavaScript), mirroring the official Receita Federal algorithm described in Instrução Normativa RFB nº 2.119/2022 (Anexo Único). PHP (server-side, inc/billing.php): - libresign_validate_cpf(): standard Módulo 11, weights 10..2 / 11..2 - libresign_validate_cnpj(): Módulo 11, weights 2–9 right-to-left (cycling), character values via ord(char)−48 so uppercase letters A–Z yield 17–42 as specified in the RFB ASCII table - Handles both legacy numeric CNPJs and the new alphanumeric format (positions 1–12 alphanumeric, positions 13–14 numeric check digits) - woocommerce_blocks_validate_additional_checkout_field hook rejects the order if the submitted value fails CPF or CNPJ validation JavaScript (client-side, same file): - Identical validateCpf() / validateCnpj() / validateCpfCnpj() functions - Auto-detects CPF (11 digits after stripping) vs CNPJ (14 chars) - isBeforeProcessing subscriber now shows 'Please enter a valid CPF or CNPJ.' (INVALID_MSG) when the value is present but fails validation, in addition to the existing empty-field error All test cases verified in browser console including the exact example CNPJ from the PDF (12.ABC.345/01DE-35 → DV 35 ✓). Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
wp.data.dispatch() notifies subscribers synchronously within the same call stack. The previous subscriber code called clearValidationError / setValidationErrors from within the subscriber itself, which triggered a re-entrant subscriber call before wasBeforeProcessing was updated. in the nested call, it dispatched again, causing infinite recursion and a 'Maximum call stack size exceeded' RangeError that permanently froze the checkout form (no typing possible until page reload). The fix applies two complementary protections: 1. isDispatching flag: any re-entrant subscriber invocation returns immediately, cutting the recursion before it starts. 2. prevWas pattern: wasBeforeProcessing is updated to isBefore BEFORE the dispatch call (not after), so that even without the flag a nested call would see the updated value and skip the block. 3. The same isDispatching guard is applied to the document 'input' event listener that calls clearValidationError, preventing a subscriber triggered by that call from re-entering. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
billing.php was growing too large by mixing two distinct concerns: - billing field registration and show/hide by country - CPF/CNPJ Módulo 11 validation (PHP algorithms + hooks + client-side JS) Split into focused files: - inc/billing.php: field registration, required-for-BR contextual filter, CSS + show/hide JS only (~160 lines) - inc/cpf-cnpj.php: libresign_validate_cpf(), libresign_validate_cnpj(), woocommerce_blocks_validate_additional_checkout_field hook, and the wp.data subscriber JS with validateCpf/Cnpj/CpfCnpj and initValidation (~240 lines) No behaviour change. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
…npj.php Both hooks configure the libresign/cpf-cnpj field specifically, so they belong in the same file as validation. billing.php now contains only the display concern: CSS + show/hide JS based on billing country. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
billing.php had no independent purpose — its sole content (CSS + show/hide JS) was specific to the libresign/cpf-cnpj field, the same as everything in cpf-cnpj.php. Merged into a single wp_footer action with one IIFE, eliminating duplicated declarations of FIELD_KEY, COUNTRY_SELECTORS and getCountry(). The bootstrap now calls init() which covers both visibility (updateVisibility + observer) and validation (initValidation). Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
The checkout page (and any other page that does not load the webhook fragment header) renders the site logo via get_custom_logo(). If the logo upload is absent from the local wp-content/uploads directory — as happens with a fresh Docker volume or staging environment — the <img> tag resolves to a broken image. Restore libresign_filter_custom_logo(), libresign_custom_logo_needs_fallback() and libresign_get_theme_logo_url() that were incorrectly removed in commit 387f505 on the assumption that the header always comes from the webhook fragment. That assumption holds for the main site header but not for simplified block-template headers (e.g. checkout). Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
Logo fallback (inc/theme-setup.php): - Restore libresign_filter_custom_logo() and helpers removed in 387f505. The assumption 'header always comes from webhook fragment' is false for the checkout page, which uses its own simplified block template part. - Fix srcset handling: the original fallback only checked the src file. WordPress generates a srcset that references resized thumbnails (e.g. logo-300x132.webp) which may not exist in fresh environments. The browser selects one of those candidates and gets a 404, making the entire image fail to load even though the original file exists. Updated libresign_custom_logo_needs_fallback() to check every URL in both src and srcset attributes; a single missing file triggers fallback. - When fallback is needed, patch the existing logo HTML in-place: replace only src and remove srcset/sizes, keeping all other attributes (width, height, class, alt) that WordPress generated from the block settings. Checkout header (parts/checkout-header.html): - Remove wp:site-title block. The logo alone is sufficient to identify the brand during checkout; showing the site title alongside the logo is redundant and adds visual noise on a distraction-free page. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
The logo fallback functions were added back to inc/theme-setup.php after being incorrectly removed in commit 387f505, but that file's scope is theme bootstrap (textdomain, block stylesheets, pattern categories) — not logo rendering logic. Extract into inc/logo.php following the same dedicated-file convention used for cpf-cnpj.php, checkout.php, guest-access.php, etc. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
The site has two logo SVGs: - logo-2.svg — for light backgrounds (checkout, account pages) - logo.svg — for dark backgrounds When the fallback is active (local upload thumbnails absent), wrap the <img> in a <picture> element with two <source> elements so the browser automatically picks the right logo from the system color-scheme setting without any JavaScript. The <img> src defaults to logo-2.svg for light mode and for browsers that do not support prefers-color-scheme. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
This file is generated/controlled by the marketing site (LibreSign/site). It must not be edited manually in the theme — changes go through the site build and are deployed here. Our local edit (removing wp:site-title) was incorrect; reverted to the version on main. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
logo.svg = dark-coloured logo, legible on light/white backgrounds logo-2.svg = pale/light logo, legible on dark backgrounds The previous mapping was inverted: logo-2.svg was being served on light backgrounds (white checkout page), making the logo nearly invisible. Swapped so logo.svg is the default for light mode. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
page-home-blogging.php and page-home-business.php were starter-kit patterns from the FSE scaffold that should have been removed in the previous boilerplate cleanup (commit 2c43b9d, which already removed 27 others). The libresign_pattern_categories() registration is also boilerplate that only existed to group those two patterns in the editor. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
libresign_block_stylesheets() and button-outline.css add a hover style for core/button is-style-outline blocks. Neither the style nor the CSS file is referenced by any template, template part, or theme.json in this project. Both are unused scaffold boilerplate. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Removes the custom account shell with product list from the login/register page, cleans up boilerplate inherited from the starter theme, splits the monolithic
functions.phpinto focused files, fixes several purchase-flow issues, and adds Brazilian billing compliance (CPF/CNPJ field with Módulo 11 validation).Changes
Account page
Remove
libresign_render_account_store_preview()and all related functions (active-tab resolver, custom login/register forms, product plans list, inline CSS shell, JS tabs).UX rationale: removes product selection and promotional content from the account page so users can focus on the immediate task of signing in or creating an account. This avoids reopening a product decision already made earlier in the purchase flow.
Guest account page now delegates to WooCommerce's native
[woocommerce_my_account]shortcode; thewoocommerce/myaccount/form-login.phptemplate override handles the form.Registration form
woocommerce/myaccount/form-login.phptemplate override with workspace fields (full name, email, password, terms acceptance) in English.organisationfield from registration — billing data (CPF/CNPJ) is collected at checkout and required only for Brazilian customers viawoocommerce_register_additional_checkout_field.Brazilian billing compliance (CPF/CNPJ)
All logic lives in a single
inc/cpf-cnpj.phpfile that owns the complete lifecycle of thelibresign/cpf-cnpjcheckout field:woocommerce_register_additional_checkout_field(WooCommerce Blocks 8.7+) in the billing address section, shown only for Brazilian customers.woocommerce_get_contextual_fields_for_locationflipsrequired: trueat submission time when the billing country is Brazil; non-BR customers are never blocked.libresign_validate_cpf,libresign_validate_cnpj) uses the Módulo 11 algorithm specified in IN RFB 2.119/2022 (Anexo Único). Handles both legacy numeric CNPJs and the new alphanumeric format (positions 1–12 alphanumeric, positions 13–14 numeric check digits; character values viaord(char) − 48). Enforced viawoocommerce_blocks_validate_additional_checkout_field.wp.data.dispatch('wc/store/validation').setValidationErrors().wp.data.dispatch()notifies subscribers synchronously within the same call stack. CallingclearValidationError/setValidationErrorsfrom inside the subscriber triggered re-entrant calls beforewasBeforeProcessingwas updated, causing aMaximum call stack size exceededRangeError that permanently froze the checkout form until page reload. Fixed with anisDispatchingre-entrancy guard and theprevWaspattern (update state before dispatching).Architecture
functions.php(909 lines) into nine focusedinc/files:theme-setup,account,registration,product,cpf-cnpj,checkout,guest-access,footer-fragment,github-site-webhook.libresign_translate_account_menu_items()andlibresign_translate_account_gettext()— array-of-translations hacks replaced by properload_theme_textdomain()+__()/esc_html_e()calls.libresign-domainmsgidstrings from Portuguese to English; addlanguages/libresign.pot(413 strings) andlanguages/libresign-pt_BR.po/.mo..github/workflows/update-pot.yml: regenerates.poton every push tomainthat touches PHP files and notifies Weblate to pull.Cleanup of versioned boilerplate (from initial scaffold commit
d797db4)The first commit of this repository (13/05/2026) used a WordPress FSE block-theme generator that bundled 56 generic patterns and several template variants as boilerplate. These files were never customised for LibreSign and were never referenced by any active route on this site. They are now removed:
home.html,archive.html,single.html,search.html(no blog configured),page-with-sidebar.html,single-with-sidebar.html,page-no-title.html,page-wide.html(no page uses these templates).arrow-icon-details,checkmark-list,arrow-link,asterisk,pill— none reachable from a rendered template after the template cleanup.libresign_get_theme_logo_url()and related — the header is always provided by the webhook fragment, soget_custom_logo()is never called.Purchase flow fixes
Do not replace

woocommerce/product-buttonin archive listings — WooCommerce already shows "Select options" linking to the product page for variable products.Do not replace
woocommerce/add-to-cart-form— guests can configure variants and add to cart; the redirect to login happens at/cart/or/checkout/vialibresign_redirect_guests_from_purchase_flow().Hide variation attributes from the "Additional information" tab via
woocommerce_display_product_attributesfilter — they are already visible in the variation selector.Fix
wpautopinjecting<br>inside WooCommerce form HTML on account pages.Testing
Tested locally via Docker (
account.libresign.coopsubdomain):redirect_topreserved12.ABC.345/01DE-35(alphanumeric CNPJ) validates correctly